/*
背景
图形编辑器（graphical editor）允许用户改变位图图像，比如大家经常用到的Photoshop。它所采用的改变方法和文本编辑器允许修改文档的方法一样。位图图像由MxN 的像素矩阵来表示，并且每个像素点都有给定的颜色。

我们的任务就是来要编写一个程序来模拟一个简单的交互式图形编辑器，并将生成的图片存储到一个 BMP 格式的文件中。

输入
输入由一组编辑命令序列组成，每条序列占一行。每个命令都是由一个大写字母表示的，且放在每行序列首字符的位置上。如果命令需要带参数，那么给出的 参数将和命令放在同一行，并用空格相互隔开。 像素点的坐标用两个整数表示，列坐标的范围是从1到M，而行坐标的范围则是从1到N（1 < M, N <= 250）。坐标原点位于矩阵的左上角，像素点的颜色是一个六位的十六进制数（如 FF8800），此数字表示该像素点的 RGB 取值。

	下面描述了图形编辑器可以接收的命令内容：

	I M N	表示产生一个新的MxN大小的图像，并且图像中所有像素点的初始颜色都为白色（FFFFFF）。
	G X Y C	表示把当前坐标点改为(X, Y)，把当前颜色置为(C)。
	C	通过把所有像素点设置为白色（FFFFFF）的方法来清除表格。且矩阵的大小保持不变。
	L X Y C	表示把坐标为（X，Y）的像素点的颜色涂成颜色（C）。
	V X Y1 Y2 C	表示画一条颜色为（C）的垂直线段，线段的列坐标为X，行坐标在Y1到Y2之间，并且包括Y1和Y2两点。
	H X1 X2 Y C	表示画一条颜色为（C）的水平线段，线段的行坐标为Y，列坐标在X1到X2之间，并且包括X1和X2两点。
	K X1 Y1 X2 Y2 C	表示画一个填充颜色为（C）的矩形，坐标（X1，Y1）和（X2，Y2）表示矩形相对的两个角。
	F X Y C	表示用颜色（C）填充区域R。区域R的定义如下：像素点（X，Y）属于区域R。和像素点（X，Y）颜色一样，并且与区域R内的任何像 素点共享一个公共边的其他任何像素点也都属于区域R。
	S Name	表示将文件保存为名为 Name 的文件，文件名长度不会超过12个字符。
	X	程序退出。
	输出
	执行 S NAME 命令时，将文件名保存为以该名称命名的 BMP 格式的文件。程序无需输出测试用例中"期待的输出”一栏的内容（该栏数据仅作为程序的判分依据使用），只需正常输出 BMP 文件即可。

	BMP 是在 Windows 上使用的位图格式，普通的 BMP 格式的文件包括两个部分，前面的部分是文件头，其中包括关于图形的参数，后半部分是每一个像素点的颜色。本题目要输出的 BMP 文件采用不压缩的 24 位色，因此 BMP 文件头部的取值如下表：

	偏移量	字节数	十六进制取值	取值	描述
	0h	2	42 4D	"BM"	幻数(无符号 66, 77)
	2h	4	46 00 00 00	70 Bytes	BMP 文件的尺寸
	6h	2	00 00	0	为应用程序保留位置
	8h	2	00 00	0	为应用程序保留位置
	Ah	4	36 00 00 00	54 bytes	位图数据开始的位置
	Eh	4	28 00 00 00	40 bytes	从此位置到文件头结束的字节数
	12h	4	02 00 00 00	2 pixels	位图文件的宽度（像素数）
	16h	4	02 00 00 00	2 pixels	位图文件的高度（像素数）
	1Ah	2	01 00	1 plane	调色板数
	1Ch	2	18 00	24 bits	每个像素的位数
	1Eh	4	00 00 00 00	0	BI_RGB, 不压缩
	22h	4	10 00 00 00	16 bytes	BMP 数据的尺寸
	26h	4	13 0B 00 00	2, 835 pixels / meter	横向每米像素数
	2Ah	4	13 0B 00 00	2, 835 pixels / meter	纵向每米像素数
	2Eh	4	00 00 00 00	0 colors	调色板中的颜色数
	32h	4	00 00 00 00	0 important colors	所有颜色都很重要
	本题目中，以上表格中蓝色背景的部分是需要根据图像的尺寸进行调整的，其余的部分则取固定的值。

	在 24 位色的位图文件的图像数据部分，每个像素点是用三个字节表示的，记录了这个点的 BGR 颜色取值。整个位图的数据是按照自底向上、从左至右的顺序存储的，即首先存储最下面一行最左侧点的颜色，然后是它右侧的点，最下一行存储完毕后，是下面第二行。每一行的数据字节数都必须为 4 的倍数，不足的用 0 补齐。譬如每行有 5 个像素，存储一共要 15 个字节，应当加一个字节补齐为 16 个字节。

	关于 BMP 文件的更多内容，可以参考维基百科。第一个测试用例生成的 one.bmp 和 two.bmp，可以用第 13 题的 hexdump 显示其内容。
*/



#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(_WIN32) && !defined(__cplusplus)
#define inline __inline
#endif

#pragma pack(1)

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;

typedef  struct  tagBITMAPFILEHEADER {
	WORD	bfType;       //位图文件的类型，必须为BM 
	DWORD	bfSize;       //文件大小，以字节为单位
	WORD	bfReserverd1; //位图文件保留字，必须为0 
	WORD	bfReserverd2; //位图文件保留字，必须为0 
	DWORD	bfbfOffBits;  //位图文件头到数据的偏移量，以字节为单位
}BITMAPFILEHEADER;

typedef  struct {
	DWORD	biSize;				//该结构的大小，字节为单位
	DWORD	biWidth;			//图形宽度以象素为单位
	DWORD	biHeight;			//图形高度以象素为单位
	WORD	biPlanes;			//目标设备的级别，必须为1 
	WORD	biBitcount;			//颜色深度，每个象素所需要的位数
	DWORD 	biCompression;		//位图的压缩类型
	DWORD	biSizeImage;		//位图的大小，以字节为单位
	DWORD	biXPelsPermeter;	//位图水平分辨率，每米像素数
	DWORD	biYPelsPermeter;	//位图垂直分辨率，每米像素数
	DWORD	biClrUsed;			//位图实际使用的颜色表中的颜色数
	DWORD	biClrImportant;		//位图显示过程中重要的颜色数
}BITMAPINFOHEADER;

typedef struct {
	BYTE    rgbRed;
	BYTE    rgbGreen;
	BYTE    rgbBlue;
} PIXEL, *PPIXEL;

typedef  struct {
	BITMAPFILEHEADER  BitmapFileHeader; //文件信息区
	BITMAPINFOHEADER  BitmapInfoHeader; //图象信息区
	PPIXEL pPixel;
}BMP;

#define MAX_INPUT_LENGTH 20

void CreatBmp(BMP *bmp, int width, int height)
{
	memset(bmp, 0, sizeof(BMP));
	bmp->BitmapFileHeader.bfType = 0x4d42;
	bmp->BitmapFileHeader.bfbfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bmp->BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmp->BitmapInfoHeader.biPlanes = 1;
	bmp->BitmapInfoHeader.biBitcount = sizeof(PIXEL) * 8;
	bmp->BitmapInfoHeader.biXPelsPermeter = 0x0b13;
	bmp->BitmapInfoHeader.biYPelsPermeter = 0x0b13;

	bmp->BitmapInfoHeader.biWidth = width;
	bmp->BitmapInfoHeader.biHeight = height;
	int iDataSizePerLine = (width * bmp->BitmapInfoHeader.biBitcount + 31) / 32 * 4;
	bmp->BitmapInfoHeader.biSizeImage = iDataSizePerLine * height;
	bmp->BitmapFileHeader.bfSize = bmp->BitmapInfoHeader.biSizeImage + bmp->BitmapFileHeader.bfbfOffBits;
	/*
		if (bmp->pData != NULL) free(bmp->pData);
		bmp->pData = (BYTE *)calloc(1, bmp->BitmapInfoHeader.biSizeImage);

		BYTE *p = bmp->pData;
		for (int i = 0; i < height; i++)
		{
			memset(p, 0xFF, bmp->BitmapInfoHeader.biWidth * 3);
			p += iDataSizePerLine;
		}
	*/
	if (bmp->pPixel != NULL) free(bmp->pPixel);
	bmp->pPixel = (PPIXEL)malloc(sizeof(PIXEL) * width * height);
	memset(bmp->pPixel, 0xFF, sizeof(PIXEL) * width * height);
}

void Fill(BMP *bmp, int x, int y, const BYTE srcColor[3], const BYTE destColor[3])
{
	int width = bmp->BitmapInfoHeader.biWidth;
	int height = bmp->BitmapInfoHeader.biHeight;

	if (x < 0 || y < 0 || x >= width || y >= height) return;

	PPIXEL curColor = &bmp->pPixel[x + y * bmp->BitmapInfoHeader.biWidth];
	if (curColor->rgbRed == srcColor[0] && curColor->rgbGreen == srcColor[1] && curColor->rgbBlue == srcColor[2])
	{
		memcpy(curColor, destColor, sizeof(PIXEL));
		Fill(bmp, x + 1, y, srcColor, destColor);
		Fill(bmp, x - 1, y, srcColor, destColor);
		Fill(bmp, x, y + 1, srcColor, destColor);
		Fill(bmp, x, y - 1, srcColor, destColor);
	}
}

void SaveBmp(const BMP *bmp, const char *fileName)
{
	FILE *fp = fopen(fileName, "wb");
	if (fp == NULL) return;
	fwrite(&bmp->BitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
	fflush(fp);
	fwrite(&bmp->BitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
	fflush(fp);
	int iDataSizePerLine = (bmp->BitmapInfoHeader.biWidth * bmp->BitmapInfoHeader.biBitcount + 31) / 32 * 4;
	int iRemainSizePerLine = iDataSizePerLine - bmp->BitmapInfoHeader.biWidth * bmp->BitmapInfoHeader.biBitcount / 8;
	for (int i = bmp->BitmapInfoHeader.biHeight - 1; i >= 0; i--)
	{
		fwrite(&bmp->pPixel[i * bmp->BitmapInfoHeader.biWidth], sizeof(PIXEL), bmp->BitmapInfoHeader.biWidth, fp);
		if (iRemainSizePerLine != 0) fwrite("", 1, iRemainSizePerLine, fp);
		fflush(fp);
	}

	fclose(fp);
}

int main()
{

	BMP bmp;
	bmp.pPixel = NULL;

	char input[MAX_INPUT_LENGTH] = {0};
	char *p = &input[2];

	while (1)
	{
		fgets(input, MAX_INPUT_LENGTH, stdin);
		switch (input[0])
		{
			case 'X':
				return 0;

			case 'I': // I M N	表示产生一个新的MxN大小的图像，并且图像中所有像素点的初始颜色都为白色（FFFFFF）。
			{
				int M, N;
				sscanf(p, "%d%d", &M, &N);
				CreatBmp(&bmp, M, N);
				break;
			}

			case 'L':
			case 'G': // G X Y C	表示把当前坐标点改为 (X, Y)，把当前颜色置为 (C)。
			{
				int X, Y, C;
				sscanf(p, "%d%d%x", &X, &Y, &C);
				--X;
				--Y;
				memcpy(&bmp.pPixel[X + Y * bmp.BitmapInfoHeader.biWidth], &C, sizeof(PIXEL));
				break;
			}

			case 'C': // C	通过把所有像素点设置为白色（FFFFFF）的方法来清除表格。且矩阵的大小保持不变。
				memset(bmp.pPixel, 0xFF, sizeof(PIXEL) * bmp.BitmapInfoHeader.biWidth * bmp.BitmapInfoHeader.biHeight);
				break;

				/*
							case 'L': // L X Y C	表示把坐标为（X，Y）的像素点的颜色涂成颜色（C）。
								break;
				*/

			case 'V': // V X Y1 Y2 C	表示画一条颜色为（C）的垂直线段，线段的列坐标为X，行坐标在Y1到Y2之间，并且包括Y1和Y2两点。
			{
				int X, Y1, Y2, C;
				sscanf(p, "%d%d%d%x", &X, &Y1, &Y2, &C);
				--X;
				--Y1;
				--Y2;
				for (int i = Y1; i <= Y2; i++)
				{
					memcpy(&bmp.pPixel[X + i * bmp.BitmapInfoHeader.biWidth], &C, sizeof(PIXEL));
				}
				break;
			}

			case 'H': // H X1 X2 Y C	表示画一条颜色为（C）的水平线段，线段的行坐标为Y，列坐标在X1到X2之间，并且包括X1和X2两点。
			{
				int X1, X2, Y, C;
				sscanf(p, "%d%d%d%x", &X1, &X2, &Y, &C);
				--X1;
				--X2;
				--Y;
				for (int i = X1; i <= X2; i++)
				{
					memcpy(&bmp.pPixel[i + Y * bmp.BitmapInfoHeader.biWidth], &C, sizeof(PIXEL));
				}
				break;
			}

			case 'K': // K X1 Y1 X2 Y2 C	表示画一个填充颜色为（C）的矩形，坐标（X1，Y1）和（X2，Y2）表示矩形相对的两个角。
			{
				int X1, X2, Y1, Y2, C;
				sscanf(p, "%d%d%d%d%x", &X1, &X2, &Y1, &Y2, &C);
				--X1;
				--X2;
				--Y1;
				--Y2;
				for (int i = Y1; i <= Y2; i++)
				{
					for (int j = X1; j <= X2; j++)
					{
						memcpy(&bmp.pPixel[j + i * bmp.BitmapInfoHeader.biWidth], &C, sizeof(PIXEL));
					}
				}
				break;
			}

			case 'F': // F X Y C	表示用颜色（C）填充区域R。区域R的定义如下：像素点（X，Y）属于区域R。
						// 和像素点（X，Y）颜色一样，并且与区域R内的任何像 素点共享一个公共边的其他任何像素点也都属于区域R。
			{
				int X, Y, C;
				sscanf(p, "%d%d%x", &X, &Y, &C);
				--X;
				--Y;
				PIXEL curColor = bmp.pPixel[X + Y * bmp.BitmapInfoHeader.biWidth];
				Fill(&bmp, X, Y, (BYTE *)(&curColor), (BYTE *)(&C));
				break;
			}
			break;

			case 'S': // S Name	表示将文件保存为名为 Name 的文件，文件名长度不会超过12个字符。
			{
				char name[20] = {0};
				sscanf(p, "%s", name);
				SaveBmp(&bmp, name);
				break;
			}
		}
	}
}